import { WebSocket, WebSocketServer } from "ws";
import { isPortOccupied } from "../utils/utils";

export default class WsServer {
  port
  server;
  onMessage: Array<(dataBuffer, ws) => void> = [];
  onClose: Array<(ws) => void> = [];
  pingIntervalTime = 3000;
  pingIntervalID;

  constructor(port = 3001) {
    isPortOccupied(port, (occupied) => {
      if (!occupied) {
        this.port = port
        this.server = new WebSocketServer({ port: port });

        this.connect()

        this.pingIntervalID = setInterval(
          () => this.ping(),
          this.pingIntervalTime
        );
      }
    });
  }
  // 心跳
  heartbeat(ws) {
    ws.isAlive = true;
  }

  ping() {
    this.broadcast((ws) => {
      if (ws.isAlive === false) return ws.terminate();
      ws.isAlive = false;
      ws.ping();
    })
  }
  // 广播
  broadcast(handle: (clinet) => void) {
    for (const client of this.server.clients) {
      if (client.readyState === WebSocket.OPEN) {
        handle(client)
      }
    }
  }

  connect() {
    this.server.on("connection", (ws, request) => {
      // 客户端会自动发送pong
      ws.on("pong", () => this.heartbeat(ws));

      ws.on("message", (dataBuffer) => {
        // json数据可直接JSON.parse(dataBuffer)
        this.onMessage.forEach((callbackfn) => {
          callbackfn.call(this, dataBuffer, ws)
        })
      });

      ws.on("close", () => {
        this.onClose.forEach((callbackfn) => {
          callbackfn.call(this, ws)
        })
      });
    });

    this.server.on("close", () => {
      clearInterval(this.pingIntervalID);
    });
  }
}
